﻿
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Odyssey.Utils;
using System.Linq;
using System.Windows.Media.Imaging;
using Odyssey.Controls.Models;
using Microsoft.Phone.Shell;

namespace Odyssey.Controls.Primitives
{
    /// <summary>
    /// Hosts a ContextMenu while being opened.
    /// </summary>
    [TemplateVisualState(Name = "Above", GroupName = "OrientationStates")]
    [TemplateVisualState(Name = "Below", GroupName = "OrientationStates")]
    [TemplatePart(Name = "PART_TouchTarget", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "PART_Background", Type = typeof(Border))]
    [TemplatePart(Name = "PART_ItemsPanel", Type = typeof(FrameworkElement))]
    public class ContextMenuOverlay : Overlay
    {

        internal ContextMenuOverlay(ContextMenuViewModel viewModel, FrameworkElement nestedElement)
            : base(nestedElement)
        {
            if (viewModel == null) throw new ArgumentNullException("viewModel");
            this.ViewModel = viewModel;
            DefaultStyleKey = typeof(ContextMenuOverlay);
        }


        protected ContextMenuViewModel ViewModel { get; private set; }
        private FrameworkElement touchTarget;
        private DispatcherTimer thresholdTimer;
        private Border pageHost;
        private Storyboard selectedElementDisabler;


        /// <summary>
        /// Gets whether the context menu is opened and transitions have completed.
        /// </summary>
        public bool IsOpened
        {
            get { return (bool)GetValue(IsOpenedProperty); }
            private set { SetValue(IsOpenedProperty, value); }
        }

        public static readonly DependencyProperty IsOpenedProperty =
            DependencyProperty.Register("IsOpened", typeof(bool), typeof(ContextMenuOverlay), new PropertyMetadata(false));


        /// <summary>
        /// Gets or sets whether the context menu appears above the selected item, otherwise it appears below.
        /// </summary>
        public bool IsAbove
        {
            get { return (bool)GetValue(IsAboveProperty); }
            set { SetValue(IsAboveProperty, value); }
        }

        public static readonly DependencyProperty IsAboveProperty =
            DependencyProperty.Register("IsAbove", typeof(bool), typeof(ContextMenuOverlay), new PropertyMetadata(false));



        /// <summary>
        /// Gets or sets the horizontal offset of the selected item.
        /// </summary>
        public double HorizontalOffset
        {
            get { return (double)GetValue(HorizontalOffsetProperty); }
            set { SetValue(HorizontalOffsetProperty, value); }
        }

        public static readonly DependencyProperty HorizontalOffsetProperty =
            DependencyProperty.Register("HorizontalOffset", typeof(double), typeof(ContextMenuOverlay), new PropertyMetadata(0.0));



        /// <summary>
        /// Gets or sets the vertical offset of the selected item.
        /// </summary>
        public double VerticalOffset
        {
            get { return (double)GetValue(VerticalOffsetProperty); }
            set { SetValue(VerticalOffsetProperty, value); }
        }

        public static readonly DependencyProperty VerticalOffsetProperty =
            DependencyProperty.Register("VerticalOffset", typeof(double), typeof(ContextMenuOverlay), new PropertyMetadata(0.0));



        /// <summary>
        /// Gets or sets the Image that represents the selected item.
        /// </summary>
        public ImageSource ItemImage
        {
            get { return (ImageSource)GetValue(ItemImageProperty); }
            set { SetValue(ItemImageProperty, value); }
        }

        public static readonly DependencyProperty ItemImageProperty =
            DependencyProperty.Register("ItemImage", typeof(ImageSource), typeof(ContextMenuOverlay), new PropertyMetadata(null));



        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            touchTarget = GetTemplateChild("PART_TouchTarget") as FrameworkElement;
            if (touchTarget != null)
            {
                touchTarget.ManipulationCompleted += (s, e) => { if (!e.Handled) IsOpen = false; };
            }
            FrameworkElement itemsPanel = GetTemplateChild("PART_ItemsPanel") as FrameworkElement;
            if (itemsPanel != null)
            {
                itemsPanel.ManipulationCompleted += (s, e) => e.Handled = true;
            }

            pageHost = GetTemplateChild("PART_Background") as Border;
            if (pageHost != null) pageHost.Child = Page;
            VisualStateManager.GoToState(this, IsAbove ? "Above" : "Below", false);

        }


        protected override void OnOpening()
        {
            ContextMenu.SetIsOpen(ViewModel.Element, true);
            CreateSelectedElementDisabler();
            base.OnOpening();
            selectedElementDisabler.Begin();
            StartThresholdTimer();
        }

        protected override void ReplaceApplicationBar()
        {
            if (ApplicationBar == null && Page.ApplicationBar != null) ApplicationBar = new ApplicationBar();
            base.ReplaceApplicationBar();
        }

        private void StartThresholdTimer()
        {
            thresholdTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(0.4),
            };
            thresholdTimer.Tick += delegate
            {
                IsOpened = true;
                StopThresholdTimer();
            };
            Dispatcher.BeginInvoke(delegate
            {
                Dispatcher.BeginInvoke(delegate
                {
                    var ts = thresholdTimer;
                    if (ts != null)
                    {
                        ts.Start();
                    }
                });
            });
        }

        private void StopThresholdTimer()
        {
            if (thresholdTimer != null && thresholdTimer.IsEnabled)
            {
                thresholdTimer.Stop();
            }
            thresholdTimer = null;
        }

        private void CreateSelectedElementDisabler()
        {
            selectedElementDisabler = new Storyboard();

            Timeline timeline = new DoubleAnimation
            {
                To = 0.0,
                Duration = TimeSpan.FromMilliseconds(0.0),
            };
            Storyboard.SetTarget(timeline, ViewModel.Control);
            Storyboard.SetTargetProperty(timeline, new PropertyPath("Opacity"));
            selectedElementDisabler.Children.Add(timeline);
        }

        protected override void OnClosing()
        {
            ContextMenu.SetIsOpen(ViewModel.Element, false);
            StopThresholdTimer();
            base.OnClosing();
        }

        protected override void OnOpened()
        {
            base.OnOpened();
            StopThresholdTimer();
            IsOpened = true;
        }

        protected override void OnClosed()
        {
            base.OnClosed();
            IsOpened = false;
            if (selectedElementDisabler != null) selectedElementDisabler.Stop();
            selectedElementDisabler = null;
        }

        protected override void CloseReplaced()
        {
            if (pageHost != null)
            {
                pageHost.Child = null;
            }
            base.CloseReplaced();
        }

        protected override void OnPageUnloaded(object sender, RoutedEventArgs e)
        {
            //base.OnPageUnloaded(sender, e);
        }
    }
}
